﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Assets.Scripts.Example;
using Assets.Scripts.Example_2;
using Assets.Scripts.Example4;
using Assets.Scripts.Example5;
using Assets.Scripts.Logic;
using Assets.Scripts.Util.StringUtil;
using LumenWorks.Framework.IO.Csv;
using UnityEngine;

public enum EnumExample
{
    invalid = -1,
    example1 = 0,
    example2 = 1,
    example3 = 2,
    example4 = 3,
    example5 = 4,
    example6 = 5,
    example7 = 6,
    example8 = 7,
    end = 8
}

public class Example : BaseExample
{
    private int _actorCount;
    private List<Actor> _actorList;
    private List<SubBtn> _containers = new List<SubBtn>();
    private EnumExample _currentEnumExample;
    private ItemResourceManager _itemResourceManager;
    public UIGrid m_Grid;

    public UIPrefabPool m_PrefabPool;

    public void Init(EnumExample exampleIndex)
    {
        _currentEnumExample = exampleIndex;
        var btnCount = ExampleHelper.GetBtnCount(_currentEnumExample);
        m_PrefabPool.SetSpawnCount(btnCount, ref _containers);
        var param = new SubBtnParam();
        for (var i = 0; i < btnCount; i++)
        {
            param.Reset();
            param.m_exampleType = _currentEnumExample;
            param.m_btnIndex = i;
            param.m_ClickAction = OnBtnClick;
            param.m_BtnName = ExampleHelper.GetSubBtnLabel(_currentEnumExample, i);
            param.m_Description = ExampleHelper.GetExampleDesc(_currentEnumExample, i);
            _containers[i].Init(param);
        }

        m_Grid.Reposition();
    }

    private void OnBtnClick(EnumExample exampleType, int btnIndex)
    {
        OnRelease();
        switch (exampleType)
        {
            case EnumExample.example1:
                OnExample1BtnClick(btnIndex);
                break;
            case EnumExample.example2:
                OnExample2BtnClick(btnIndex);
                break;
            case EnumExample.example3:
                OnExample3BtnClick(btnIndex);
                break;
            case EnumExample.example4:
                OnExample4BtnClick(btnIndex);
                break;
            case EnumExample.example5:
                OnExample5BtnClick(btnIndex);
                break;
            case EnumExample.example6:
                OnExample6BtnClick(btnIndex);
                break;
            case EnumExample.example7:
                OnExample7BtnClick(btnIndex);
                break;
            case EnumExample.example8:
                OnExample8BtnClick(btnIndex);
                break;
            default:
                throw new ArgumentOutOfRangeException("exampleType", exampleType, null);
        }
    }


    public override void OnRelease()
    {
        base.OnRelease();

        _testCamera = false;
        _useManager = false;
        _testRay = false;
        _useNonAlloc = false;
        _usePool = false;

        if (poolTestEntityList != null)
        {
            for (int i = 0; i < poolTestEntityList.Count; i++)
            {
                Destroy(poolTestEntityList[i].gameObject);
            }

            poolTestEntityList = null;
        }

        if (rayEntityList != null)
        {
            for (var i = 0; i < rayEntityList.Count; i++)
            {
                Destroy(rayEntityList[i].gameObject);
            }

            rayEntityList = null;
        }

        if (objList != null)
        {
            for (var i = 0; i < objList.Count; i++)
            {
                Destroy(objList[i]);
            }

            objList = null;
        }

        if (player2List != null)
        {
            for (var i = 0; i < player2List.Count; i++)
            {
                Destroy(player2List[i].m_Obj);
            }

            player2List = null;
        }

        if (player2ArrayList != null)
        {
            for (var i = 0; i < player2ArrayList.Count; i++)
            {
                var player = (Player2) player2ArrayList[i];
                if (player != null)
                {
                    Destroy(player.m_Obj);
                }
            }

            player2ArrayList = null;
        }

        if (player3List != null)
        {
            for (var i = 0; i < player3List.Count; i++)
            {
                Destroy(player3List[i].m_Obj);
            }

            player3List = null;
        }
    }

    private void Update()
    {
        if (_actorList != null && _actorList.Count > 0)
        {
            for (var i = 0; i < _actorList.Count; i++)
            {
                _actorList[i].Update(Time.deltaTime);
            }
        }

        if (poolTestEntityList != null)
        {
            for (var i = 0; i < poolTestEntityList.Count; i++)
            {
                poolTestEntityList[i].OnUpdate(_usePool);
            }
        }

        if (_testCamera)
        {
            if (_useManager)
            {
                var camera = MainCameraManager.GetMainCamera();
            }
            else
            {
                var camera = Camera.main;
            }
        }

        if (_testRay)
        {
            if (rayEntityList != null)
            {
                for (var i = 0; i < rayEntityList.Count; i++)
                {
                    rayEntityList[i].OnUpdate(_useNonAlloc);
                }
            }
        }
    }

    private void LateUpdate()
    {
        if (_actorList != null && _actorList.Count > 0)
        {
            for (var i = 0; i < _actorList.Count; i++)
            {
                _actorList[i].LateUpdate(Time.deltaTime);
            }
        }
    }

    #region Example1

    /// <summary>
    ///     Example1的按钮点击.
    /// </summary>
    private void OnExample1BtnClick(int btnIndex)
    {
        if (btnIndex == 0)
        {
            Consts.EXAMPLE1_USE_BYTES = false;
            Consts.EXAMPLE1_USE_CAPACITY = false;
            TaskManager.Instance.StartTask(InitConfig());
        }
        else if (btnIndex == 1)
        {
            Consts.EXAMPLE1_USE_BYTES = true;
            Consts.EXAMPLE1_USE_CAPACITY = false;
            TaskManager.Instance.StartTask(InitConfig());
        }
        else if (btnIndex == 2)
        {
            Consts.EXAMPLE1_USE_BYTES = true;
            Consts.EXAMPLE1_USE_CAPACITY = true;
            TaskManager.Instance.StartTask(InitConfig());
        }
        else if (btnIndex == 3)
        {
            Consts.EXAMPLE1_USE_BYTES = true;
            Consts.EXAMPLE1_USE_CAPACITY = true;
            TaskManager.Instance.StartTask(ReadMultiConfig());
        }
        else if (btnIndex == 4)
        {
            Consts.EXAMPLE1_USE_BYTES = true;
            Consts.EXAMPLE1_USE_CAPACITY = true;
            TaskManager.Instance.StartTask(ReadMultiConfigFraming());
        }
    }

    /// <summary>
    ///     读取单个配置.
    /// </summary>
    private IEnumerator InitConfig()
    {
        XMLObjectRegister.RegistAllObject();
        if (_itemResourceManager == null)
        {
            _itemResourceManager = new ItemResourceManager();
        }

        yield return _itemResourceManager.Init();
    }

    /// <summary>
    ///     一次性读取多个配置.
    /// </summary>
    private IEnumerator ReadMultiConfig()
    {
        XMLObjectRegister.RegistAllObject();
        if (_itemResourceManager == null)
        {
            _itemResourceManager = new ItemResourceManager();
        }

        MonoProfiler.BeginSample("begin [ItemResourceManager][ReadConfigWithBytes]");
        for (var i = 0; i < Consts.EXAMPLE1_MULTI_CONFIG_COUNT; i++)
        {
            yield return _itemResourceManager.Init();
        }

        MonoProfiler.BeginSampleWithoutGC("end [ItemResourceManager][ReadConfigWithBytes]");
    }

    /// <summary>
    ///     分帧读取多个配置.
    /// </summary>
    private IEnumerator ReadMultiConfigFraming()
    {
        XMLObjectRegister.RegistAllObject();
        if (_itemResourceManager == null)
        {
            _itemResourceManager = new ItemResourceManager();
        }

        var fp = new FramingProcessing(Consts.EXAMPLE1_FRAME);
        MonoProfiler.BeginSample("begin [ItemResourceManager][ReadConfigWithBytes]");
        for (var i = 0; i < Consts.EXAMPLE1_MULTI_CONFIG_COUNT; i++)
        {
            yield return _itemResourceManager.Init();
            yield return fp.UpdateFrame();
        }

        MonoProfiler.BeginSampleWithoutGC("end [ItemResourceManager][ReadConfigWithBytes]");
    }

    #endregion

    #region Example2

    /// <summary>
    ///     Example2的按钮点击.
    /// </summary>
    private void OnExample2BtnClick(int btnIndex)
    {
        if (btnIndex == 0)
        {
            UpdateInMono();
        }
        else if (btnIndex == 1)
        {
            UpdateInList();
        }
        else if (btnIndex == 2)
        {
            UpdateInArrayList();
        }
        else if (btnIndex == 3)
        {
            CountDownTest(false);
        }
        else if (btnIndex == 4)
        {
            CountDownTest(true);
        }
    }

    private List<GameObject> objList;

    private void UpdateInMono()
    {
        objList = new List<GameObject>();
        var Cube = (GameObject) Resources.Load(Consts.EXAMPLE2_CUBE_PATH);
        for (var i = 0; i < Consts.EXAMPLE2_PALYER_COUNT; i++)
        {
            var obj = Instantiate(Cube);
            obj.AddComponent<Player1>();
            objList.Add(obj);
        }
    }

    private List<Player2> player2List;

    private void UpdateInList()
    {
        player2List = new List<Player2>();
        var Cube = (GameObject) Resources.Load(Consts.EXAMPLE2_CUBE_PATH);
        for (var i = 0; i < Consts.EXAMPLE2_PALYER_COUNT; i++)
        {
            var player = new Player2();
            player.m_Obj = Instantiate(Cube);
            player2List.Add(player);
        }
    }

    private ArrayList player2ArrayList;

    private void UpdateInArrayList()
    {
        player2ArrayList = new ArrayList();
        var Cube = (GameObject) Resources.Load(Consts.EXAMPLE2_CUBE_PATH);
        for (var i = 0; i < Consts.EXAMPLE2_PALYER_COUNT; i++)
        {
            var player = new Player2();
            player.m_Obj = Instantiate(Cube);
            player2ArrayList.Add(player);
        }
    }

    private List<Player3> player3List;

    private void CountDownTest(bool useTimer)
    {
        player3List = new List<Player3>();
        var Cube = (GameObject) Resources.Load(Consts.EXAMPLE2_CUBE_PATH);
        for (var i = 0; i < Consts.EXAMPLE2_PALYER_COUNT; i++)
        {
            var player = new Player3();
            player.m_Obj = Instantiate(Cube);
            player.Init(useTimer);
            player3List.Add(player);
        }
    }

    #endregion

    #region Example3

    /// <summary>
    ///     Example3的按钮点击.
    /// </summary>
    private void OnExample3BtnClick(int btnIndex)
    {
        if (btnIndex == 0)
        {
            PrintLog(false);
        }
        else if (btnIndex == 1)
        {
            PrintLog(true);
        }
    }

    private void PrintLog(bool useLogWrapper)
    {
        MonoProfiler.BeginSample("[Example][PrintLog] start");
        if (useLogWrapper)
        {
            for (var i = 0; i < Consts.EXAMPLE3_LOG_COUNT; i++)
            {
                LogWrapper.LogDebug("这是第", i, "个测试log。");
            }
        }
        else
        {
            for (var i = 0; i < Consts.EXAMPLE3_LOG_COUNT; i++)
            {
                Debug.Log("这是第" + i + "个测试log。");
            }
        }

        MonoProfiler.BeginSampleWithoutGC("[Example][PrintLog] end");
    }

    #endregion

    #region Example4

    /// <summary>
    ///     Example4的按钮点击.
    /// </summary>
    private void OnExample4BtnClick(int btnIndex)
    {
        if (btnIndex == 0)
        {
            TestClass();
        }
        else if (btnIndex == 1)
        {
            TestStruct();
        }
        else if (btnIndex == 2)
        {
            StructMemPoint();
        }
    }

    private void TestClass()
    {
        MonoProfiler.BeginSample("MyClass所占内存  start");
        for (var i = 0; i < Consts.EXAMPLE4_ENTITY_COUNT; i++)
        {
            var c = new MyClass();
        }

        MonoProfiler.BeginSampleWithoutGC("MyClass所占内存  end");
    }

    private void TestStruct()
    {
        MonoProfiler.BeginSample("MyStruct所占内存  start");
        for (var i = 0; i < Consts.EXAMPLE4_ENTITY_COUNT; i++)
        {
            var c = new MyStruct();
        }

        MonoProfiler.BeginSampleWithoutGC("MyStruct所占内存  end");
    }

    private void StructMemPoint()
    {
        unsafe
        {
            var size = sizeof(MyStruct);
            LogWrapper.LogError("MyStruct size:", size);
            size = sizeof(TestStruct);
            LogWrapper.LogError("TestStruct size:", size);
            size = sizeof(TestStruct2);
            LogWrapper.LogError("TestStruct2 size:", size);
        }

        Console.ReadLine();
    }

    #endregion

    #region Example5

    /// <summary>
    ///     Example5的按钮点击.
    /// </summary>
    private void OnExample5BtnClick(int btnIndex)
    {
        if (btnIndex == 0)
        {
            TestCamera(false);
        }
        else if (btnIndex == 1)
        {
            TestCamera(true);
        }
        else if (btnIndex == 2)
        {
            TestRay(false);
        }
        else if (btnIndex == 3)
        {
            TestRay(true);
        }
    }

    private bool _testCamera;
    private bool _useManager;

    private void TestCamera(bool useManager)
    {
        objList = new List<GameObject>();
        var Cube = (GameObject) Resources.Load(Consts.EXAMPLE2_CUBE_PATH);
        for (var i = 0; i < Consts.EXAMPLE5_CAMERA_TEST_COUNT; i++)
        {
            var obj = Instantiate(Cube);
            objList.Add(obj);
        }

        _testCamera = true;
        _useManager = useManager;
    }

    private List<RayEntity> rayEntityList;
    private bool _testRay;
    private bool _useNonAlloc;

    private void TestRay(bool useUnAlloc)
    {
        rayEntityList = new List<RayEntity>();
        var Cube = (GameObject) Resources.Load(Consts.EXAMPLE2_CUBE_PATH);
        for (var i = 0; i < Consts.EXAMPLE5_RAY_TEST_COUNT; i++)
        {
            var obj = Instantiate(Cube);
            var entity = obj.AddComponent<RayEntity>();
            rayEntityList.Add(entity);
        }

        _testRay = true;
        _useNonAlloc = useUnAlloc;
    }

    #endregion

    #region Example6

    /// <summary>
    ///     Example6的按钮点击.
    /// </summary>
    private void OnExample6BtnClick(int btnIndex)
    {
        if (btnIndex == 0)
        {
            TestPool(false);
        }
        else if (btnIndex == 1)
        {
            TestPool(true);
        }
    }

    private List<PoolTestEntity> poolTestEntityList;
    private bool _usePool;

    private void TestPool(bool usePool)
    {
        poolTestEntityList = new List<PoolTestEntity>();
        var Cube = (GameObject) Resources.Load(Consts.EXAMPLE2_CUBE_PATH);
        for (var i = 0; i < Consts.EXAMPLE6_POOL_TEST_COUNT; i++)
        {
            var obj = Instantiate(Cube);
            var entity = obj.AddComponent<PoolTestEntity>();
            poolTestEntityList.Add(entity);
        }

        _usePool = usePool;
    }

    #endregion

    #region Example7

    /// <summary>
    ///     Example6的按钮点击.
    /// </summary>
    private void OnExample7BtnClick(int btnIndex)
    {
        if (btnIndex == 0)
        {
            ReadCSV();
        }
        else if (btnIndex == 1)
        {
            ReadCSV_New();
        }
    }

    private Dictionary<string, ResInfo> m_all_res_list = new Dictionary<string, ResInfo>();

    /// <summary>
    ///     使用读取文本的方式读取CSV.
    ///     需要手动将res_list_v16_v0.csv放到PERSISTENT目录.
    /// </summary>
    public void ReadCSV_New()
    {
        var new_res_list_path =
            Path.Combine(FileUtil.GetRootPath(EnumFileType.PERSISTENT), "res_list_v16_v0.csv");
        MonoProfiler.WriteLogToFile(new_res_list_path);
        var hasCurResList = FileUtil.CheckFileExist(new_res_list_path, EnumFileType.PERSISTENT);
        if (hasCurResList)
        {
            LogWrapper.LogError("开始读csv");
            MonoProfiler.BeginSample("---------    ReadText Start:   -----------");
            m_all_res_list = new Dictionary<string, ResInfo>(31000);
            var reader = new StreamReader(File.OpenRead(new_res_list_path));
            var index = 0;
            while (!reader.EndOfStream)
            {
                var line = reader.ReadLine();
                if (index == 0)
                {
                    index++;
                    continue;
                }

                index++;
                var values = line.Split(',');
                ResInfo res_info = new CDNResInfo(values[1], int.Parse(values[2]), int.Parse(values[4]), values[5]);
                m_all_res_list.Add(res_info.path, res_info);
            }

            MonoProfiler.BeginSample("---------    ReadText END:   -----------");
        }
        else
        {
            LogWrapper.LogError("找不到csv");
        }

        MonoProfiler.WriteLogToFile("Dict.count:" + m_all_res_list.Count);
    }

    /// <summary>
    ///     使用三方插件读取CSV.
    /// </summary>
    public void ReadCSV()
    {
        m_all_res_list.Clear();
        var new_res_list_path =
            Path.Combine(FileUtil.GetRootPath(EnumFileType.PERSISTENT), "res_list_v16_v0.csv");
        MonoProfiler.WriteLogToFile(new_res_list_path);
        var has_cur_res_list = FileUtil.CheckFileExist(new_res_list_path, EnumFileType.PERSISTENT);
        if (has_cur_res_list)
        {
            MonoProfiler.BeginSample("---------    ReadCSV Start:   -----------");
            LogWrapper.LogError("开始读csv");
            var bytes = FileUtil.ReadFileToBytes(new_res_list_path, EnumFileType.PERSISTENT);
            m_all_res_list = ParseResList(bytes);
            MonoProfiler.BeginSample("---------    ReadCSV END:   -----------");
        }
        else
        {
            LogWrapper.LogError("找不到csv");
        }

        MonoProfiler.WriteLogToFile("Dict.count:" + m_all_res_list.Count);
    }

    /// <summary>
    ///     解析资源索引表.读取测试csv文件需要的结构.
    /// </summary>
    private Dictionary<string, ResInfo> ParseResList(byte[] bytes)
    {
        var res_list = new Dictionary<string, ResInfo>(31000);

        try
        {
            using (var reader = new CsvReader(new StringReader(FileUtil.GetUTF8String(bytes)), true, ','))
            {
                var index = 0;
                while (reader.ReadNextRecord())
                {
                    ResInfo res_info = new CDNResInfo(reader["res_path"], int.Parse(reader["group_id"]),
                        int.Parse(reader["res_size_byte"]), reader["crc32"]);
                    res_list.Add(res_info.path, res_info);
                    index++;
                }
            }
        }
        catch (Exception e)
        {
            LogWrapper.LogError("[ResourceDownloader]ParseResList error:", e.Message);
        }

        return res_list;
    }

    /// <summary>
    ///     读取测试csv文件需要的结构.
    /// </summary>
    public class CDNResInfo : ResInfo
    {
        public int crc32;

        public CDNResInfo(string path, int group_id, long total_size_btye, string crc32)
            : base(path, group_id, total_size_btye, "")
        {
            this.crc32 = int.Parse(crc32);
        }
    }

    /// <summary>
    ///     读取测试csv文件需要的结构.
    /// </summary>
    public class ResInfo
    {
        public int download_size_btye; //int最大表示2G的量。所以这里用int就行
        public byte group_id;
        public string path;
        public int total_size_btye; //int最大表示2G的量。所以这里用int就行

        public ResInfo(string path, int group_id, long total_size_btye, string md5)
        {
            this.path = path;
            this.group_id = (byte) group_id;
            download_size_btye = 0;
            this.total_size_btye = (int) total_size_btye;
        }
    }

    #endregion

    #region Example8

    /// <summary>
    ///     Example6的按钮点击.
    /// </summary>
    private void OnExample8BtnClick(int btnIndex)
    {
        if (btnIndex == 0)
        {
            TestSplitString(false);
        }
        else if (btnIndex == 1)
        {
            TestSplitString(true);
        }
        else if (btnIndex == 2)
        {
            TestSubString(false);
        }
        else if (btnIndex == 3)
        {
            TestSubString(true);
        }
    }

    private void TestSplitString(bool useUtil)
    {
        var testStr = "1,2,3";
        var strs = new string[3];

        if (useUtil)
        {
            for (var i = 0; i < Consts.EXAMPLE8_STRING_COUNT; i++)
            {
                StringUtil.Split(testStr, ',', strs);
            }
        }
        else
        {
            for (var i = 0; i < Consts.EXAMPLE8_STRING_COUNT; i++)
            {
                strs = testStr.Split(',');
            }
        }
    }

    private void TestSubString(bool useUtil)
    {
        var testStr = "1234567890";

        if (useUtil)
        {
            for (var i = 0; i < Consts.EXAMPLE8_STRING_COUNT; i++)
            {
                var subString = StringUtil.SubString(testStr, 3, 3);
            }
        }
        else
        {
            for (var i = 0; i < Consts.EXAMPLE8_STRING_COUNT; i++)
            {
                var subStr = testStr.Substring(3, 3);
            }
        }
    }

    #endregion
}